/**
* AutoSWF - Cody Cushing. March 26, 2009
* Copyright (c) 2009 Cody Cushing
* No use restrictions. Maintain this notice in all versions. 
**/

package com.autoswf.tracker
{
	import com.autoswf.core.Transport;
	
	import flexunit.framework.TestCase;

	public class AsyncTrackerTest extends TestCase
	{
		public var mockProperty:String = "val";
		public var mockProperty2:String = "val2";
		
		private var tracker:AsyncTracker;
		private var client:MockTrackClient;
		
		public function AsyncTrackerTest(methodName:String=null)
		{
			super(methodName);
		}
		
		override public function setUp():void
		{
			client = new MockTrackClient();
			tracker = new AsyncTracker("AsyncTracker");
			tracker.addClient(client, "mockTrackClientId");
			tracker.client = this;
		}
		
		/**
		 * support loading different definitions
		 */		
		public function testMultipleDefinitions():void
		{
			var expected:XML = <definitions/>;
			expected.appendChild(sync01XML);
			expected.appendChild(sync02XML);
			
			tracker.addDefinition(sync01XML);
			tracker.addDefinition(sync02XML);
			
			assertEquals(expected, tracker.definitions);
		}
		
		/**
		 * support pulling id matches from seperate definitions
		 */		
		public function testMultipleClients():void
		{
			tracker.addDefinition(sync01XML);
			tracker.addDefinition(sync01_aXML);

			tracker.sendUpChain(new Transport("sync01"));
			assertEquals("url/?name=value,s1_t1", client.results.toString());
		}
		private static const sync01_aXML:XML =
          <definition id="service1" pattern="{token}" handler="mockTrackClientId">
            <node id="{token}" trigger="sync01" pattern="s1_t1"/>
          </definition>
        

		/**
		 * support triggering multiple nodes off a single id
		 */
		public function testMultipleTriggerMatches():void
		{
			tracker.addDefinition(definition3);

			tracker.sendUpChain(new Transport("id01"));
			assertEquals("s3_t1,s3_t2,s3_t3", client.results.toString());
		}
		private static const definition3:XML =
        <definition id="service2" pattern="{token}" handler="mockTrackClientId">
          <node id="{token}" trigger="id01" pattern="s3_t1"/>
          <node id="{token}" trigger="id01" pattern="s3_t2"/>
          <node id="{token}" trigger="id01" pattern="s3_t3"/>
        </definition>
		
		
		/**
		 * send simple value after trigger 
		 */		
		public function testSync01():void
		{
			tracker.addDefinition(sync01XML);
			tracker.sendUpChain(new Transport("sync01"));
			assertEquals("url/?name=value", client.sendResult);
		}
		private static const sync01XML:XML = 
        <definition id="root" pattern="url/{token}" handler="mockTrackClientId">
          <node id="{token}" trigger="sync01" pattern="?name=value"/>
        </definition>
		
		/**
		 * inject a constant and property
		 */        
		public function testSync02():void
		{
			tracker.addDefinition(sync02XML);
			tracker.sendUpChain(new Transport("sync02"));
			assertEquals("url/?name=val", client.sendResult);
		}
		private static const sync02XML:XML =
		<definition id="root" pattern="url/{token}" handler="mockTrackClientId">
          <node id="{token}" trigger="sync02" pattern="?{0}={1}">
            <constant id="{0}" value="name" />
            <property id="{1}" path="mockProperty" />
          </node>
        </definition>
		
		/**
		 * use a constant to transform a returned property
		 */		
		public function testSync03():void
		{
			tracker.addDefinition(sync03XML);
			tracker.sendUpChain(new Transport("sync03"));
			assertEquals("url/?name=newValue", client.sendResult);
		}
		private static const sync03XML:XML =
		<definition id="root" pattern="url/{token}" handler="mockTrackClientId">
          <node id="{token}" trigger="sync03" pattern="?{0}={1}">
            <constant id="{0}" value="name" />
            <property id="{1}" path="mockProperty" />
            <constant id="name=val" value="name=newValue" />
          </node>
        </definition>

		/**
		 * inject constant and property after an asyncronous trigger
		 */		
		public function testAsync01():void
		{
			tracker.addDefinition(async01XML);
			tracker.sendUpChain(new Transport("async01_T1"));
			tracker.sendUpChain(new Transport("async01_T2"));
			assertEquals("url/?name1=value&name2=val", client.sendResult);
		}
		private static const async01XML:XML =
		<definition id="root" pattern="url/{token}" handler="mockTrackClientId">
          <node id="{token}" trigger="async01_T1" pattern="?name1=value{async}">
            <node id="{async}" trigger="async01_T2" pattern="&{0}={1}">
              <constant id="{0}" value="name2" />
              <property id="{1}" path="mockProperty" />
            </node>
          </node>
        </definition>
            
		/**
		 * nested asyncronous triggers
		 */		
		public function testAsync02():void
		{
			tracker.addDefinition(async02XML);
			tracker.sendUpChain(new Transport("async02_T1"));
			tracker.sendUpChain(new Transport("async02_T2"));
			tracker.sendUpChain(new Transport("async02_T3"));
			assertEquals("url/name.val", client.sendResult);
		}
		private static const async02XML:XML =
		<definition id="root" pattern="url/{0}" handler="mockTrackClientId">
          <node id="{0}" trigger="async02_T1" pattern="{1}">
            <node id="{1}" trigger="async02_T2" pattern="{2}">
              <node id="{2}" trigger="async02_T3" pattern="name.{3}">
                <property id="{3}" path="mockProperty" />
              </node>
            </node>
          </node>
        </definition>
		
		/**
		 * nested node with same trigger as parent
		 * to do: trigger is executing parent and child node with same trigger
		 */		
		public function testAsync03():void
		{
			tracker.addDefinition(async03XML);
			tracker.sendUpChain(new Transport("async03_T1"));
			tracker.sendUpChain(new Transport("async03_T2"));
			assertEquals("url/name.val", client.sendResult);
		}
		private static const async03XML:XML =
		<definition id="root" pattern="url/{0}" handler="mockTrackClientId">
          <node id="{0}" trigger="async03_T1" pattern="{1}">
            <node id="{1}" trigger="async03_T2" pattern="{2}">
              <node id="{2}" trigger="async03_T2" pattern="name.{3}">
                <property id="{3}" path="mockProperty" />
              </node>
            </node>
          </node>
        </definition>
		
		/**
		 * mixed syncronous and asyncronous injecting
		 */		
		public function testAsync04():void
		{
			tracker.addDefinition(async04XML);
			tracker.sendUpChain(new Transport("async04_T1"));
			tracker.sendUpChain(new Transport("async04_T2"));
			assertEquals("url/val.name,val|name", client.sendResult);
		}
		private static const async04XML:XML = 
		<definition id="root" pattern="url/{0}" handler="mockTrackClientId">
          <node id="{0}" trigger="async04_T1" pattern="{1},{a}|{b}">
            <node id="{1}" trigger="async04_T2" pattern="{2}.{3}">
              <property id="{2}" path="mockProperty" />
              <constant id="{3}" value="name" />
            </node>
            <property id="{a}" path="mockProperty" />
            <constant id="{b}" value="name" />
          </node>
        </definition>
		
		/**
		 * multiple async triggers
		 */		
		public function testAsync05():void
		{
			tracker.addDefinition(async05XML);
			tracker.sendUpChain(new Transport("async05_T1"));
			tracker.sendUpChain(new Transport("async05_T3"));
			tracker.sendUpChain(new Transport("async05_T2"));
			assertEquals("url/name1.val|name2.val", client.sendResult);
		}
		private static const async05XML:XML =
		<definition id="root" pattern="url/{0}" handler="mockTrackClientId">
          <node id="{0}" trigger="async05_T1" pattern="{1}|{4}">
            <node id="{1}" trigger="async05_T2" pattern="name1.{3}">
              <property id="{3}" path="mockProperty" />
            </node>
            <node id="{4}" trigger="async05_T3" pattern="name2.{5}">
              <property id="{5}" path="mockProperty" />
            </node>
          </node>
        </definition>
            
		/**
		 * multiple syncronous and asyncronous and nested syncronous injection, also verifies
		 * tracks arent sent before all triggers.
		 */		
		public function testAsync06():void
		{
			tracker.addDefinition(async06XML);
			tracker.sendUpChain(new Transport("async06_T1"));
			tracker.sendUpChain(new Transport("async06_T2"));
			tracker.sendUpChain(new Transport("async06_T3"));
			assertNull("track sent before all triggers", client.sendResult);
			tracker.sendUpChain(new Transport("async06_T4"));
			assertEquals("url/val_1/val_2/val_3/val_4/val_5?cond=val", client.sendResult);
		}
		private static const async06XML:XML =
		<definition id="root" pattern="url/{0}" handler="mockTrackClientId">
          <node id="{0}" trigger="async06_T1" pattern="{1}_1/{2}/{3}_3/{4}/{6}_5?{5}">
            <property id="{1}" path="mockProperty" />
            <node id="{2}" trigger="async06_T2" pattern="{a}_2">
              <property id="{a}" path="mockProperty" />
            </node>
            <property id="{3}" path="mockProperty" />
            <node id="{4}" trigger="async06_T3" pattern="{b}_4">
              <property id="{b}" path="mockProperty" />
              <node id="{5}" trigger="async06_T4" pattern="cond={a}">
                <property id="{a}" path="mockProperty" />
              </node>
            </node>
            <property id="{6}" path="mockProperty" />
          </node>
        </definition>
        

		/**
		 * Inline token populated with global property
		 */		
		public function testDeclarative01():void
		{
			tracker.addDefinition(declarative01XML);
			tracker.sendUpChain(new Transport("async01_T1"));
			assertEquals("url/name=val", client.sendResult);
		}
		private static const declarative01XML:XML =
		<definition id="root" pattern="url/{0}" handler="mockTrackClientId">
		  <property id="{glob}" path="mockProperty" />
          <node id="{0}" trigger="async01_T1" pattern="name={glob}"/>
        </definition>
        
        /**
		 * Inline token for global overwriten by local node
		 */		
		public function testDeclarative02():void
		{
			tracker.addDefinition(declarative02XML);
			tracker.sendUpChain(new Transport("async01_T1"));
			assertEquals("url/name=val2", client.sendResult);
		}
		private static const declarative02XML:XML =
		<definition id="root" pattern="url/{0}" handler="mockTrackClientId">
		  <property id="{glob}" path="mockProperty" />
          <node id="{0}" trigger="async01_T1" pattern="name={glob}">
            <property id="{glob}" path="mockProperty2" />
          </node>
        </definition>
        
	}
}


